package service

import (
	"codeGenerator/pool"
	"codeGenerator/tools"
	"codeGenerator/variable"
	"os"
	"strings"
	"text/template"
)

type CodeAutoSrv struct {
	Tool *tools.Tools
	Pool *pool.SimplePool
}

func NewCodeAutoSrv() *CodeAutoSrv {
	return &CodeAutoSrv{
		Tool: tools.NewTools(),
		Pool: pool.NewSimplePoll(variable.NUMBER),
	}
}

func (cas *CodeAutoSrv) Generator(codeInfoList []map[string]interface{}) interface{} {
	fm := template.FuncMap{
		"Lower": cas.Tool.Lower,
		"Snake": cas.Tool.ToSnake,
	}

	//rootpath := "F:/test/go"

	var content_list []string

	for _, codeInfo := range codeInfoList {
		codeInfo := codeInfo

		cas.Pool.Add(func() error {
			suffix := codeInfo["suffix"].(string)
			projectName := codeInfo["projectName"].(string)
			rootpath := codeInfo["rootpath"].(string)

			template_path := codeInfo["template_path"].(string)
			//if template_path == ""{
			//	template_path = "./template"
			//}

			//switch suffix {
			//case "java":
			//	rootpath = ""
			//case "py":
			//	rootpath = "F:/test/py"
			//}

			if !(codeInfo["isCustom"].(bool)) {
				if !cas.Tool.Exists(rootpath + "/" + projectName) {
					if err := os.Mkdir(rootpath+"/"+projectName, os.ModePerm); err != nil {
						return err
					}
				}

				for index, dir := range variable.MODULARLIST {
					if (index >= 6 && suffix != "go") || (index >= 4 && suffix == "java") {
						break
					}

					if !cas.Tool.Exists(rootpath + "/" + projectName + "/" + dir) {
						if err := os.Mkdir(rootpath+"/"+projectName+"/"+dir, os.ModePerm); err != nil {
							return err
						}
					}
				}

				structList := codeInfo["structList"].([]interface{})

				for _, value := range structList {
					entity := value.(map[string]interface{})

					entity["projectName"] = projectName

					entity["structName"] = cas.Tool.Capitalize(entity["structName"].(string))
					if entity["structName"].(string) == "User" || entity["structName"].(string) == "Account" {
						entity["isUser"] = true
					}
					entity["length"] = len(entity["fieldNameList"].([]interface{})) - 1

					tmpl_map := make(map[*template.Template]*os.File)
					var file *os.File

					if !cas.Tool.Exists(rootpath + "/" + projectName + "/" + "main." + suffix) {
						file, _ = os.Create(rootpath + "/" + projectName + "/" + "main." + suffix)
						tmpl_map[template.Must(template.New("main.tpl").Funcs(fm).
							ParseFiles(template_path+"/"+suffix+"/main.tpl"))] = file
					}

					for modular, attach := range variable.MODULARMAP {
						if (suffix == "java" || suffix == "py") && (modular == "route" ||
							modular == "middleware" || modular == "variable") {
							continue
						}

						if suffix == "java" && modular == "database" {
							continue
						}

						filepath := rootpath + "/" + projectName + "/" + modular + "/"

						if modular == "model" || modular == "service" || modular == "controller" || modular == "route" {
							filepath = filepath + cas.Tool.Lower(entity["structName"].(string)) + attach + suffix
						} else {
							filepath = filepath + attach + suffix
						}

						if !cas.Tool.Exists(filepath) {
							file, _ = os.Create(filepath)
							tmpl_map[template.Must(template.New(modular+".tpl").Funcs(fm).
								ParseFiles(template_path+"/"+suffix+"/"+modular+".tpl"))] = file
						}
					}

					if suffix == "py" {
						for _, v := range []string{"model", "controller", "variable"} {
							filepath := rootpath + "/" + projectName + "/" + v + "/__init__." + suffix
							var tpl *template.Template

							if !cas.Tool.Exists(filepath) {
								file, _ = os.Create(filepath)

								switch v {
								case "model":
									tpl = template.Must(template.New("baseclass.tpl").Funcs(fm).
										ParseFiles(template_path + "/" + suffix + "/baseclass.tpl"))
								case "controller":
									tpl = template.Must(template.New("__init__.tpl").Funcs(fm).
										ParseFiles(template_path + "/" + suffix + "/__init__.tpl"))
								case "variable":
									tpl = template.Must(template.New("variable.tpl").Funcs(fm).
										ParseFiles(template_path + "/" + suffix + "/variable.tpl"))
								}

								tmpl_map[tpl] = file
							}
						}
					}

					for tmpl, file := range tmpl_map {
						//if err := tmpl.Execute(file, entity); err != nil {
						//	return err
						//}
						err := tmpl.Execute(file, entity)
						file.Close()
						if err != nil {
							return err
						}
					}
				}
			} else {
				codeInfo["structName"] = cas.Tool.Capitalize(codeInfo["structName"].(string))
				codeInfo["length"] = len(codeInfo["fieldNameList"].([]interface{})) - 1

				if suffix == "go" {
					for _, value := range codeInfo["fieldNameList"].([]interface{}) {
						fieldMap := value.(map[string]interface{})
						if fieldMap["isNew"].(bool) {
							fieldMap["FieldPackageName"] = strings.Split(fieldMap["FieldType"].(string), ".")[0]
						}
					}
				}

				file, _ := os.Create("./out/toBeCopied." + suffix)
				tmpl := template.Must(template.New("customize.tpl").Funcs(fm).
					ParseFiles("./template/" + suffix + "/customize.tpl"))

				if err := tmpl.Execute(file, codeInfo); err != nil {
					return err
				}
			}

			if suffix == "go" && !codeInfo["isCustom"].(bool) {
				cas.Tool.CommandLine(rootpath+"/"+projectName, "go", "mod", "init", projectName)
				cas.Tool.CommandLine(rootpath+"/"+projectName, "go", "mod", "tidy")
			}

			if codeInfo["isCustom"].(bool) {
				content, err := os.ReadFile("./out/toBeCopied." + suffix)
				if err != nil {
					return err
				}

				content_list = append(content_list, string(content))
			}

			return nil
		})
	}

	cas.Pool.Run()

	return content_list
}

func (cas *CodeAutoSrv) Zip(projectName string) {
	cas.Tool.CommandLine("D:/test", "7z", "a", "-tzip", "D:/test/"+projectName+".zip", "D:/test/"+projectName)
}
